﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FieldHost {
	
	public class MetaField<T> : IComparable<MetaField<T>>, IEquatable<MetaField<T>> where T : struct, IComparable {

		private readonly Dictionary<MessageType, string> _messages = new Dictionary<MessageType, string>();

		public MetaField(){
			IsBoundCheckActive = false;
            IsEditable = true;
            MinValue = default(T);
            MaxValue = default(T);
            Value = default(T);

            IsFormatApplicable = false;
            Format = String.Empty;
		}

		public bool IsBoundCheckActive{
			get;
			set;
		}

        public bool IsEditable { get; set; }

        public bool IsFormatApplicable { get; set; }

        public string Format { get; set; }

		private T _value;

		public T Value{
			get{
				return _value;
			}
			set{
				if(IsBoundCheckActive){
					if(value.CompareTo(MinValue) <= 0){
						throw new ArgumentOutOfRangeException(this.GetMessage(MessageType.MinException));
					}
					if (value.CompareTo(MaxValue) >= 0) {
						throw new ArgumentOutOfRangeException(this.GetMessage(MessageType.MaxException));
					}
				}

                if (IsEditable){
                    _value = value;
                }
			}
		}

		public T MinValue{
			get;
			set;
		}

		public T MaxValue{
			get;
			set;
		}

		public void AddMessage(MessageType type, string message){
			_messages.Add(type, message);
		}

		public string GetMessage(MessageType type){
			return _messages.ContainsKey(type) ? _messages[type] : String.Empty;
		}

        public override string ToString() {
            return IsFormatApplicable ? String.Format(Format, Value) : Value.ToString();
        }

        #region Operators Overload

        public static bool operator <(MetaField<T> me, MetaField<T> other)
        {
            return (me.CompareTo(other) < 0);
        }

        public static bool operator >(MetaField<T> me, MetaField<T> other)
        {
            return (me.CompareTo(other) > 0);
        }

        public static bool operator <=(MetaField<T> me, MetaField<T> other)
        {
            return (me.CompareTo(other) <= 0);
        }

        public static bool operator >=(MetaField<T> me, MetaField<T> other)
        {
            return (me.CompareTo(other) >= 0);
        }

        public static bool operator ==(MetaField<T> me, MetaField<T> other)
        {
			return Equals(me, other);
        }

        public static bool operator !=(MetaField<T> me, MetaField<T> other)
        {
			return !Equals(me, other);
        }

        #endregion
        
		#region IComparable<MetaField<T>> Members

		public int CompareTo(MetaField<T> other) {
			if (other.Equals(null)) {
				return -1;
			}
			return this.Value.CompareTo(other.Value);
		}

		#endregion

		#region IEquatable<MetaField<T>> Members

		public override int GetHashCode() {
			return Value.GetHashCode();
		}

		public override bool Equals(object obj) {
			if(obj == null || !(obj is MetaField<T>))
				return false;

			return Equals(obj as MetaField<T>);
		}

		public bool Equals(MetaField<T> other) {
			if(Object.Equals(other, null))
				return false;
			return (Value.CompareTo(other.Value) == 0);
		} 

		#endregion
	}
}
